home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Utilities Experience
/
The Utilities Experience - Volume 1.iso
/
software
/
rendering
/
utilities
/
real3d
/
flox
/
flox.rex
next >
Wrap
OS/2 REXX Batch file
|
1978-06-29
|
12KB
|
384 lines
/* flox.rexx - generates simulated flocking paths of a chosen number of
followers tracking
* a leader path
*
*
* Program operation:
*
* Record the definition of a bspline path in Real3D and save it as an RPL
script
* Run this program
* Give the name of the 'leader' bspline RPL script saved above
* Specify:
* total number of frames
* number of followers
* factors affecting the behaviour of each follower
* output file to save generated RPL bspline paths to
*
* The program then generates paths that follow the leader's in a pattern that
* attempts to simulate flocking behaviour.
*
* Revision History
*
* Date Who Reason
* -------------------------------------
* 25OCT94 DRO Original
* 26OCT94 DRO Added user-definable weighting for when the follower
re-calculates
* its direction to the leader.
*
*
*/
/* constants */
TRUE=(1=1)
FALSE=~TRUE
/* Set precision */
NUMERIC DIGITS 6
/* Intro */
SAY 'Flox v1.1'
SAY '---------'
SAY ''
SAY 'This program takes a Real3D B-Spline defined in an RPL script file and
uses it'
SAY 'and a number of parameters to create RPL B-Spline definitions of paths
that attempt'
SAY 'to follow the leader in a flocking pattern.'
SAY ''
SAY 'The resulting B-Splines are written to a file, which should then be
run from Real3D.'
SAY ''
SAY 'Note: you must use the macro recording feature of Real3D to define the
leader B-Spline'
SAY 'as follows:'
SAY ''
SAY '1. Select Project > Macros > Record to start recording'
SAY '2. Define the B-Spline'
SAY '3. Select Project > Macros > Record to stop recording'
SAY '4. Optionally, select Project > Macros > Current to Named, and
specify a filename'
SAY ' under which to save the RPL. Alternatively, the macro deafaults
to T:macro.rpl'
SAY ''
SAY 'I based it on a bit of thinking, which may prove to be hopelessly
inadequate ;-)'
SAY 'David Oxley, 25 October 1994, oxleyd@logica.co.uk'
SAY ''
leader_default="T:MACRO.RPL"
/* Get name of leader RPL script file */
SAY 'Enter leader RPL script filename, or Q to quit:
[default='||leader_default||'] '
PULL response
IF response = "Q" THEN EXIT 10
IF response = '' THEN response=leader_default
/* try to open file */
IF OPEN(leaderf,response,'READ') = FALSE THEN
DO
SAY 'Unable to open leader file "'||response||'".'
EXIT 10
END
/* Now scan the leader file and extract the knot point x,y,z values and
number of knots
*
* Sample RPL bspline macro script follows:
*
* 1 O_LOCK ( iLOCK_EXCL )
*
* -0.95 -1.00333 0.6
* -0.779436 -0.405667 0.6
* -0.812256 0.226 0.6
* -0.031538 0.721667 0.6
* 0.23841 -0.552667 0.6
* 0.697897 0.389 0.6
* 1.11 0.776667 0.6
* 7 ( count )
* 3 ( type )
* 0 ( geom. flags )
* 255 255 255 0 ( RGBA )
* "line" ( name )
* 65664 ( flags )
* "CEND"
* C_LINE DROP
*
* 0 O_LOCK ( iLOCK_REMOVE )
*
*
*/
/* Skip first two lines */
skip=READLN(leaderf)
skip=READLN(leaderf)
/* Now start reading the coords */
read_complete=FALSE
count=1
DO UNTIL read_complete=TRUE
line=READLN(leaderf)
PARSE VAR line leader_x.count leader_y.count leader_z.count
IF DATATYPE(leader_y.count) = 'CHAR' THEN
read_complete=TRUE
ELSE
count=count+1
END
/* Assumption now is that the value in leader_x.count is the count of knots */
leader_knots=leader_x.count
/* We must evaluate an imaginary knot point after the last point in the
leader's spline,
* by simple linear extrapolation from the last and penultimate points
* This point is necessary for calculating the aiming point for the
follower as it nears
* the end of the animation, and hence the end of the leader's spline.
*
* Conveniently, count is set to one more than the number of knot points.
Notice, however,
* that we don't include this last point in the leader_knots value.
*/
penultimate=leader_knots-1
leader_x.count=leader_x.leader_knots+(leader_x.leader_knots-leader_x.penulti
mate)
leader_y.count=leader_y.leader_knots+(leader_y.leader_knots-leader_y.penulti
mate)
leader_z.count=leader_z.leader_knots+(leader_z.leader_knots-leader_z.penulti
mate)
SAY 'Enter total number of frames for the animation, or Q to quit: '
PULL response
IF response = "Q" THEN EXIT 10
total_frames=response
/* Get an outfile that doesn't already exist. */
file_exists=FALSE
DO UNTIL response = "Q" | (response ~= "Q" & file_exists=FALSE)
SAY 'Enter output RPL script filename, or Q to quit: '
PULL response
file_exists=EXISTS(response)
IF file_exists THEN
SAY 'File '||response||' already exists. Pick another.'
END
IF response = "Q" THEN EXIT 10
outfile=response
SAY 'Enter the number of followers, or Q to quit: '
PULL response
IF response = "Q" THEN EXIT 10
num_followers=response
/* choose default values for the characteristics */
independence_default=(total_frames % leader_knots)+1
accuracy_default=0.5
offset=(ABS(leader_x.2-leader_x.1)+ABS(leader_y.2-leader_y.1)+ABS(leader_z.2
-leader_z.1))/3
proximity_default=offset/3
freedom_default=1
/* prop is the multiplication factor used to scale the direction vector
when it is
* re-targeted to the estimated position of the leader
*/
prop=leader_knots/total_frames
SAY 'Enter the distance between the leader and a follower that should be
considered close'
SAY 'enough that the two are touching, or Q to quit:
[default='||proximity_default||'] '
PULL response
IF response = "Q" THEN EXIT 10
IF response = '' THEN response=proximity_default
proximity=response
/* Now get the behaviour characteristics of each follower */
DO i=1 TO num_followers
SAY 'For follower '||i||', please enter the following values:'
SAY ''
SAY 'Independence: on average, how many frames this follower will
continue on its own course'
SAY 'for, before re-assessing its direction to the leader, or Q to quit:'
SAY '(1=always track leader, >1=be more independent)
[default='||independence_default||'] '
PULL response
IF response = "Q" THEN EXIT 10
IF response = '' THEN response=independence_default
IF response < 1 THEN response=1
IF response > total_frames THEN response=total_frames+1
independence.i=response
SAY ''
SAY 'Accuracy: on average, how good this follower is at judging its
distance from the leader,'
SAY 'or Q to quit: (0=inaccurate, 1=accurate)
[default='||accuracy_default||'] '
PULL response
IF response = "Q" THEN EXIT 10
IF response = '' THEN response=accuracy_default
IF response < 0 THEN response=0
IF response > 1 THEN response=1
accuracy.i=response
SAY ''
SAY 'Freedom: a high value will, on average, cause the follower to over
or undershoot the'
SAY 'position of the leader. A low value will tend the follower to match
the leader,'
SAY 'or Q to quit: (0=conform, >0=be free) [default='||freedom_default||'] '
PULL response
IF response = "Q" THEN EXIT 10
IF response = '' THEN response=freedom_default
IF response < 0 THEN response=0
IF response > 10 THEN response=10
freedom.i=response
SAY ''
/* Now calculate where to position this follower initially. Pretty
random, but based
* on the average of the distance between the leader's first and second
knot points.
* Same sort of thing to determine the initial direction
*/
pos_fol_x.i=leader_x.1+(RANDU()-0.5)*offset
pos_fol_y.i=leader_y.1+(RANDU()-0.5)*offset
pos_fol_z.i=leader_z.1+(RANDU()-0.5)*offset
dir_fol_x.i=(RANDU()-0.5)*offset
dir_fol_y.i=(RANDU()-0.5)*offset
dir_fol_z.i=(RANDU()-0.5)*offset
END
IF OPEN(outf,outfile,'WRITE') = FALSE THEN
DO
SAY 'Unable to open output file "'||outfile||'".'
EXIT 10
END
/* We have all the values we need, let's generate the followers' splines! */
DO i=1 TO num_followers
/* Keep the user informed */
SAY 'Follower '||i||', writing spline information...'
/* RPL object locking code at the start of each new object */
CALL WRITELN(outf,'1 O_LOCK')
CALL WRITELN(outf,'')
CALL WRITELN(outf,pos_fol_x.i||' 'pos_fol_y.i||' 'pos_fol_z.i)
curr_frame=0
/* knot_count will be written to the script file after the coords */
knot_count=1
/* ind_timer is based on the independence value for this follower, and
determines, for
* this spline segment, how long before the follower re-assesses its position relative
* to the leader (modulo arithmetic gives the integer value)
*/
ind_timer=(independence.i*judgement(accuracy.i))%1
DO UNTIL curr_frame >= total_frames
pos_fol_x.i=pos_fol_x.i+dir_fol_x.i
pos_fol_y.i=pos_fol_y.i+dir_fol_y.i
pos_fol_z.i=pos_fol_z.i+dir_fol_z.i
ind_timer=ind_timer-1
IF (ind_timer<1) | (total_frames-curr_frame)<=1 THEN
DO
/* The timer has expired, or we are on the last frame of the
animation, so we must
* write the current position to the script file.
*/
CALL WRITELN(outf,pos_fol_x.i||' 'pos_fol_y.i||' 'pos_fol_z.i)
knot_count=knot_count+1
ind_timer=independence.i*judgement(accuracy.i)
/* We must now reset the direction vector for this follower, so that
it tracks,
* closely or loosely, the current position of the leader.
*
* seg_pos tells us approximately how far along the current line
segment the leader is
*/
seg_pos=curr_frame*leader_knots/total_frames
/* use // (remainder) and % (modulo) to get the fractional and
integer parts of seg_pos */
frac=seg_pos//1
est_knot=1+(seg_pos%1)
next_knot=est_knot+1
/* Now work out the estimated position of the leader, where this
follower will aim */
est_leader_x=leader_x.est_knot+frac*(leader_x.next_knot-leader_x.est_knot)
est_leader_y=leader_y.est_knot+frac*(leader_y.next_knot-leader_y.est_knot)
est_leader_z=leader_z.est_knot+frac*(leader_z.next_knot-leader_z.est_knot)
/* Calculate the new direction vector based on the estimated position
of the leader
* as seen from this follower's current position. Scale it according
to the average
* number of frames per line segment, and according to the accuracy
of this follower.
*
* weight is a factor added to the new direction calculation that
determines how
* well the follower will eventually match the leader's position: how
"free" it is.
* It is a random value based on freedom.i, centred on 0.
*/
weight=(freedom.i*RANDU())-freedom.i/2
dir_fol_x.i=prop*(weight+(est_leader_x-pos_fol_x.i)-proximity)*judgement(acc
uracy.i)
dir_fol_y.i=prop*(weight+(est_leader_y-pos_fol_y.i)-proximity)*judgement(acc
uracy.i)
dir_fol_z.i=prop*(weight+(est_leader_z-pos_fol_z.i)-proximity)*judgement(acc
uracy.i)
END /* IF ind_timer<1 */
curr_frame=curr_frame+1
END /* DO UNTIL curr_frame >= total_frames */
/* Now append the spline information to the script file */
CALL WRITELN(outf,knot_count||' ( count )')
CALL WRITELN(outf,'3 ( type )')
CALL WRITELN(outf,'0 ( geom. flags )')
CALL WRITELN(outf,'255 255 255 0 ( RGBA )')
CALL WRITELN(outf,'"follower.'||i||'" ( name )')
CALL WRITELN(outf,'65664 ( flags )')
CALL WRITELN(outf,'"CEND"')
CALL WRITELN(outf,'C_LINE DROP')
CALL WRITELN(outf,'')
CALL WRITELN(outf,'0 O_LOCK ( iLOCK_REMOVE )')
SAY 'done.'
END /* DO i=1 TO num_followers */
IF CLOSE(outf) = FALSE THEN
DO
SAY 'Unable to close output file "'||outfile||'".'
EXIT 10
END
SAY 'All done. File '||outfile||' contains the generated spline(s).'
EXIT 0
/*
* Judgement is a weighted random function that returns a number in the
range 0.5 to 1.5,
* the weighting being controlled by 'accuracy'. Accuracy of 1 always
returns 1;
* Accuracy of 0 returns a random value in the 0.5-1.5 range.
*/
judgement: PROCEDURE
ARG accuracy
retval=(1+((1-accuracy)*(RANDU()-0.5)))
RETURN retval